package com.smartcommunity.controller.common;

import com.smartcommunity.lis.BimgClientPool;
import com.smartcommunity.lis.BimgException;
import com.smartcommunity.base.common.DataImport;
import com.smartcommunity.base.common.PicImport;
import com.smartcommunity.bean.model.Result;
import com.smartcommunity.exception.BusinessException;
import com.smartcommunity.log.interceptor.Log;
import com.smartcommunity.utils.ExcelUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.*;

/**
 * Copyright: Copyright (c) 2018
 * Company:
 *
 * @author heweiwei
 * @description 数据导入控制器
 * @date 2018/8/30
 */
@RestController
@RequestMapping(value = "/dataImport")
@Slf4j
@Api(value = "DataImportController", tags = "资源模板导入")
public class DataImportController {

    @Autowired
    private BimgClientPool lis;

    private final ApplicationContext app;

    public DataImportController(ApplicationContext app) {
        this.app = app;
    }

    /**
     * 导入Excel数据
     * @param file excel文件
     * @param type 数据类型（实有人口、实有房屋、实有单位等）
     * @param companyId 小区编码
     * @return 请求结果
     */
    @PostMapping(value = "/importCompanyPeople")
    @ApiOperation(value = "导入Excel数据",notes = "导入Excel数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "excel" ,paramType = "form", dataType="__file",value = "excel文件"),
            @ApiImplicitParam(name = "type" ,value = "导入数据类型（people:实有人口，" +
                    "build:实有楼栋，house:实有房屋，peopleHouse:人房关系，realCompany:实有单位," +
                    "realCompanyPeople:单位从业人员,realPower:实有力量,villageEntranceExit:小区出入口）"+
                    "villageOrg:行政区划,sysOrgImport:组织机构,faceLibPerson:人脸库人员信息(villageCode值设为libId)"),
            @ApiImplicitParam(name = "taskId" ,value = "跟踪excel导入进度的ID,前端由UUID随机创建"),
            @ApiImplicitParam(name = "companyId" ,value = "小区编号")
    })
    public Result realCompanyImportData(@RequestParam("excel") MultipartFile file,
                                        @RequestParam("type") String type,
                                        @RequestParam("taskId") String taskId,
                                        @RequestParam(value = "companyId", required = false) String companyId,
                                        HttpServletResponse response) throws SQLException, IllegalArgumentException, BusinessException {
        log.info("接口：importData；导入数据，type:"+type);

        Result result = new Result();
        DataImport server;
        List<Object[]> dataList;
        try {
            // 获取对应的业务逻辑bean
            server = (DataImport) app.getBean(type);

            if(StringUtils.isEmpty(companyId)){
                result.setResultCode(-1);
                result.setResultMessage("公司id必填！");
            }


            // 获取excel中的数据
            dataList = ExcelUtils.parseExcelToListArray(file);
        } catch (BeansException be) {
            log.error("数据导入时获取具体的业务逻辑bean失败！", be);
            result.setResultCode(-1);
            result.setResultMessage("数据导入时获取具体的业务逻辑bean失败！");
            return result;
        } catch (IOException ie) {
            log.error("读取Excel数据失败！", ie);
            result.setResultCode(-1);
            result.setResultMessage("读取Excel数据失败！");
            return result;
        }
        if (dataList.isEmpty()) {
            throw new BusinessException("导入的excel为空！");
        }
        // 处理excel中的数据
        String fileName = "";
        try {
            fileName = server.importData(dataList, companyId, file.getOriginalFilename(), taskId, response);
        } catch (SQLException sqlE) {
            throw sqlE;
        } catch (IllegalArgumentException ile) {
            throw ile;
        } catch (BusinessException bse) {
            throw bse;
        } catch (Exception e) {
            log.error("导入数据异常！", e);
            throw new BusinessException("上传失败，请联系管理员！");
        }

        // 组装请求结果
        Map<String, Object> resultMap = new HashMap<>(16);
        resultMap.put("type", type);
        resultMap.put("fileName",fileName);
        result.setData(resultMap);
        if(StringUtils.isNotEmpty(fileName)){
            result.setResultCode(-1);
            result.setResultMessage("导入数据失败！");
        }
        return result;
    }

    /**
     * 导入Excel数据
     * @param file excel文件
     * @param type 数据类型（实有人口、实有房屋、实有单位等）
     * @param villageCode 小区编码
     * @return 请求结果
     */
    @PostMapping(value = "/importData")
    @ApiOperation(value = "导入Excel数据",notes = "导入Excel数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "excel" ,paramType = "form", dataType="__file",value = "excel文件"),
            @ApiImplicitParam(name = "type" ,value = "导入数据类型（people:实有人口，" +
                    "build:实有楼栋，house:实有房屋，peopleHouse:人房关系，realCompany:实有单位," +
                    "realCompanyPeople:单位从业人员,realPower:实有力量,villageEntranceExit:小区出入口）"+
                    "villageOrg:行政区划,sysOrgImport:组织机构,faceLibPerson:人脸库人员信息(villageCode值设为libId)"),
            @ApiImplicitParam(name = "taskId" ,value = "跟踪excel导入进度的ID,前端由UUID随机创建"),
            @ApiImplicitParam(name = "villageCode" ,value = "小区编号")
    })
    public Result importData(@RequestParam("excel") MultipartFile file,
                             @RequestParam("type") String type,
                             @RequestParam("taskId") String taskId,
                             @RequestParam(value = "villageCode", required = false) String villageCode,
                             HttpServletResponse response) throws SQLException, IllegalArgumentException, BusinessException {
        log.info("接口：importData；导入数据，type:"+type);

        Result result = new Result();
        DataImport server;
        List<Object[]> dataList;
        try {
            // 获取对应的业务逻辑bean
            server = (DataImport) app.getBean(type);

            //如果不是导入的行政区划，组织机构,则小区编号必填
            if(StringUtils.containsNone("faceLibPerson,villageOrg,sysOrg",type)){
                if(StringUtils.isEmpty(villageCode)){
                    result.setResultCode(-1);
                    result.setResultMessage("数据导入时小区编号必填！");
                }
            }

            // 获取excel中的数据
            dataList = ExcelUtils.parseExcelToListArray(file);
        } catch (BeansException be) {
            log.error("数据导入时获取具体的业务逻辑bean失败！", be);
            result.setResultCode(-1);
            result.setResultMessage("数据导入时获取具体的业务逻辑bean失败！");
            return result;
        } catch (IOException ie) {
            log.error("读取Excel数据失败！", ie);
            result.setResultCode(-1);
            result.setResultMessage("读取Excel数据失败！");
            return result;
        }
        if (dataList.isEmpty()) {
            throw new IllegalArgumentException("导入的excel为空！");
        }
        // 处理excel中的数据
        String fileName = "";
        try {
            fileName = server.importData(dataList, villageCode, file.getOriginalFilename(), taskId, response);
        } catch (SQLException sqlE) {
            throw sqlE;
        } catch (IllegalArgumentException ile) {
            throw ile;
        } catch (BusinessException bse) {
            throw bse;
        } catch (Exception e) {
            log.error("导入数据异常！", e);
            throw new BusinessException("上传失败，请联系管理员！");
        }

        // 组装请求结果
        Map<String, Object> resultMap = new HashMap<>(16);
        resultMap.put("type", type);
        resultMap.put("fileName",fileName);
        result.setData(resultMap);
        if(StringUtils.isNotEmpty(fileName)){
            result.setResultCode(-1);
            result.setResultMessage("导入数据失败！");
        }
        return result;
    }

    /**
     * 获取Excel导入进度
     */
    @RequestMapping("/getImportDataProgress")
    @ApiOperation(value = "获取Excel导入进度", notes = "获取Excel导入进度", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "导入数据类型（people:实有人口，" +
                    "build:实有楼栋，house:实有房屋，peopleHouse:人房关系，realCompany:实有单位," +
                    "realCompanyPeople:单位从业人员,realPower:实有力量,villageEntranceExit:小区出入口）" +
                    "villageOrg:行政区划,sysOrgImport:组织机构,faceLibPerson:人脸库人员信息(villageCode值设为libId)"),
            @ApiImplicitParam(name = "taskId", value = "跟踪excel导入进度的id")
    })
    @Log(info = "获取Excel导入进度")
    public Result getImportDataProgress(String type, String taskId) {
        Result result = new Result();
        //解决bug:图片导入报错
        if(app.getBean(type) instanceof DataImport) {
	        DataImport server = (DataImport) app.getBean(type);
	        int progress = server.getImportDataProgress(taskId);
	        Map<String, Object> resultMap = new HashMap<>();
	        resultMap.put("type", type);
	        resultMap.put("progress", progress);
	        result.setData(resultMap);
        }
        return result;
    }


    @RequestMapping("/getImportPicDataProgress")
    @ApiOperation(value = "获取图片导入进度", notes = "获取图片导入进度", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "导入数据类型（peoplePic:实有人口，realCompanyPic:实有单位," +
                    "realCompanyPeoplePic:单位从业人员,realPower:实有力量,villageEntranceExitPic:小区出入口," +
                    "faceLibPerson:人脸库人员信息(villageCode设为libId)）"),
            @ApiImplicitParam(name = "taskId", value = "跟踪excel导入进度的id")
    })
    @Log(info = "获取图片导入进度")
    public Result getImportPicDataProgress(String type, String taskId) {
        Result result = new Result();
        //解决bug:图片导入报错
        if(app.getBean(type) instanceof PicImport) {
            PicImport server = (PicImport) app.getBean(type);
            int progress = server.getImportPicProgress(taskId);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("type", type);
            resultMap.put("progress", progress);
            result.setData(resultMap);
        }
        return result;
    }

    /**
     * 下载Error Excel
     */
    @RequestMapping("/downloadExcel")
    @ApiOperation(value = "下载Excel错误记录", notes = "下载Excel错误记录", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileName", value = "Error FileName", required = true)
    })
    @Log(info = "下载模板文件")
    public void downloadExcel(
            @RequestParam(name = "fileName", required = true) String fileName,
            HttpServletRequest request,
            HttpServletResponse response
    ) {
        // 设置响应参数
        response.setCharacterEncoding(request.getCharacterEncoding());
        response.setContentType("application/octet-stream");
        FileInputStream fis = null;
        File file = new File(System.getProperty("user.dir") + "/" + fileName);
        try {
            fis = new FileInputStream(file);
            // UTF-8编码，下载可以正常显示中文
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            IOUtils.copy(fis, response.getOutputStream());
            response.flushBuffer();
        } catch (FileNotFoundException e) {
            throw new BusinessException("指定类型的文件未找到！");
        } catch (IOException e) {
            throw new BusinessException("读取文件流失败！");
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new BusinessException("关闭输入流失败！");
                }
                file.delete();
            }
        }
    }

    /**
     * 导入图片
     * @return 导入结果
     */
    @PostMapping(value = "/importPic")
    @ApiOperation(value = "导入图片",notes = "导入图片")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "villageCode" ,value = "小区编号"),
            @ApiImplicitParam(name = "type" ,value = "导入数据类型（peoplePic:实有人口，realCompanyPic:实有单位," +
                    "realCompanyPeoplePic:单位从业人员,realPower:实有力量,villageEntranceExitPic:小区出入口" +
                    ",faceLibPerson:人脸库人员信息(villageCode设为libId)）"),
            @ApiImplicitParam(name = "mpFile" ,value = "要导入的图片,支持多张,多个mpFile",dataType="__file")
    })
    public Result importPic(@RequestParam(value = "mpFile", required = true) MultipartFile[] mpFiles,
                            @RequestParam(value = "type", required = true) String type,
                            @RequestParam(value = "taskId", required = true) String taskId,
                            @RequestParam(value = "villageCode", required = false) String villageCode) throws SQLException, IllegalArgumentException, BusinessException {
        log.info("接口：importPic；导入图片");
        Result result = new Result();
        // 获取对应的业务逻辑bean
        PicImport server = (PicImport) app.getBean(type);
        // 取得需要导入的图片
        List<Map<String, Object>> pathList = new ArrayList<>();
        Map<String, Object> pathMap;
        try {
            for (MultipartFile mpFile : mpFiles) {
                if (mpFile.isEmpty()) {
                    continue;
                }
                pathMap = new HashMap<>(8);
                // 设置小区编码
                pathMap.put("villageCode", villageCode);
                // 获取图片名
                String fileName = Optional.ofNullable(mpFile.getOriginalFilename())
                        .filter(StringUtils::isNotBlank).orElseGet(mpFile::getName);
                // 根据图片名获取文件名称（例如身份证号码，单位名称）
                String idNo = StringUtils.substringBeforeLast(fileName, ".");
                // 对于文件名是绝对路径的，则需要进行二次截取
                if (idNo.contains("/")) {
                    idNo = StringUtils.substringAfterLast(idNo, "/");
                }
                if (idNo.contains("\\")) {
                    idNo = StringUtils.substringAfterLast(idNo, "\\");
                }
                // 设置照片的标识
                pathMap.put("idNo", idNo);
                pathMap.put("fileName", idNo);
                byte[] bytes = mpFile.getBytes();
                // 保存到LIS
                String path = lis.uploadImageForever(bytes);
                // 设置图片保存地址
                pathMap.put("picPath", path);
                // 加入入库列表
                pathList.add(pathMap);
            }
        } catch (IOException ie) {
            log.error("读取文件流失败！", ie);
            result.setResultCode(-1);
            result.setResultMessage("读取文件流失败！");

            return result;
        } catch (BimgException pe) {
            log.error("LIS操作失败！", pe);
            result.setResultCode(-1);
            result.setResultMessage("LIS操作失败！");

            return result;
        }
        // 图片信息入库
        try {
            if(!pathList.isEmpty()){
                server.importPic(pathList,taskId);
            }
        } catch (SQLException sqlE) {
            throw sqlE;
        } catch (IllegalArgumentException ile) {
            throw ile;
        } catch (BusinessException bse) {
            throw bse;
        } catch (Exception e) {
            log.error("导入数据异常！", e);
            throw new BusinessException("上传失败，请联系管理员！");
        }

        // 组装请求结果
        Map<String, Object> resultMap = new HashMap<>(16);
        resultMap.put("type", type);
        result.setData(resultMap);

        return result;
    }

}
